﻿#region Using Statements
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
#endregion

namespace StarFox.Graphics
{
    /// <summary>
    /// Performs motion blur and bloom post-processing.
    /// </summary>
    public class PostScreenProcessor : IDisposable
    {
        #region Fields

        PostBloomProcessor postBloomProcessor;
        MotionBlurProcessor motionBlurProcessor;
        RenderTarget2D auxRT;

        #endregion

        #region Properties

        /// <summary>
        /// Sets the motion blur factor.
        /// </summary>
        public float BlurFactor { set { motionBlurProcessor.BlurFactor = value; } }

        /// <summary>
        /// Gets or sets the bloom threshold.
        /// <para>Higher values produce smaller and better defined glows, while smaller ones produce a softer end result.</para>
        /// </summary>
        public float BloomThreshold
        {
            get { return postBloomProcessor.BloomThreshold; }
            set { postBloomProcessor.BloomThreshold = value; }
        }

        /// <summary>
        /// Gets or sets the intensity of the original scene in the final combined result.
        /// </summary>
        public float BaseIntensity
        {
            get { return postBloomProcessor.BaseIntensity; }
            set { postBloomProcessor.BaseIntensity = value; }
        }

        /// <summary>
        /// Gets or sets the intensity of the resulting bloom in the final combined result.
        /// </summary>
        public float BloomIntensity
        {
            get { return postBloomProcessor.BloomIntensity; }
            set { postBloomProcessor.BloomIntensity = value; }
        }

        /// <summary>
        /// Gets or sets the color saturation of the original scene in the final combined result.
        /// </summary>
        public float BaseSaturation
        {
            get { return postBloomProcessor.BaseSaturation; }
            set { postBloomProcessor.BaseSaturation = value; }
        }

        /// <summary>
        /// Gets or sets the color saturation of the resulting bloom in the final combined result.
        /// </summary>
        public float BloomSaturation
        {
            get { return postBloomProcessor.BloomSaturation; }
            set { postBloomProcessor.BloomSaturation = value; }
        }

        /// <summary>
        /// Gets or sets the color correction factor.
        /// </summary>
        public Color Color
        {
            get { return postBloomProcessor.Color; }
            set { postBloomProcessor.Color = value; }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of this class.
        /// </summary>
        /// <param name="motionBlurEffect">The motion blur post-processing effect.</param>
        /// <param name="postBloomEffect">The bloom post-processing effect.</param>
        /// <param name="screenBorderTexture">The texture used for screen border fadeout.</param>
        public PostScreenProcessor(Effect motionBlurEffect, Effect postBloomEffect, Texture2D screenBorderTexture)
        {
            motionBlurProcessor = new MotionBlurProcessor(motionBlurEffect);
            postBloomProcessor = new PostBloomProcessor(postBloomEffect, screenBorderTexture) { BaseIntensity = 1.0f };

            auxRT = new RenderTarget2D(motionBlurEffect.GraphicsDevice,
                                       motionBlurEffect.GraphicsDevice.PresentationParameters.BackBufferWidth,
                                       motionBlurEffect.GraphicsDevice.PresentationParameters.BackBufferHeight);
        }

        #endregion

        #region Dispose

        // dispose flag
        bool isDisposed = false;

        /// <summary>
        /// Immediately releases all resources used by this object.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Allows an object to try to free resources and perform other cleanup operations before it is reclaimed by garbage collection.
        /// </summary>
        ~PostScreenProcessor()
        {
            Dispose(false);
        }

        /// <summary>
        /// Releases the unmanaged resources used by this object and optionally releases the managed resources.
        /// </summary>
        /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
        protected virtual void Dispose(bool disposing)
        {
            if (!isDisposed)
            {
                if (disposing)
                {
                    if (postBloomProcessor != null) { postBloomProcessor.Dispose(); postBloomProcessor = null; }
                    if (auxRT != null) { auxRT.Dispose(); auxRT = null; }
                }

                isDisposed = true;
            }
        }

        #endregion

        #region Apply

        /// <summary>
        /// Applies both the motion blur and bloom post-processing effects.
        /// </summary>
        /// <param name="inTexture">Texture2D used as processing input.</param>
        /// <param name="outRenderTarget">RenderTarget2D used as processing output.</param>
        public void Apply(Texture2D inTexture, RenderTarget2D outRenderTarget)
        {
            motionBlurProcessor.Apply(inTexture, auxRT);
            postBloomProcessor.Apply(auxRT, outRenderTarget);
        }

        #endregion
    }
}
